#pragma once

#include"Connect.hpp"
#include<sys/epoll.h>
#include<functional>
#include"Log.hpp"
#include"Reactor.hpp"
using namespace LogModule;

using com_t  = std::function<std::string(std::string &)>;
class IOServer:public Connection
{
    const static int sizee = 1024;
   public:
    IOServer(int sockfd)
    {
        SetNoBlock(sockfd); 
        SetEvents(EPOLLIN | EPOLLET);
        SetSockfd(sockfd);
    }
    /*  int _sockfd;
    std::string _inbuffer;
    std::string _outbuffer;
    InetAddr _peer_addr;

   Reactor* _owner;

    uint32_t _events;
};*/
    virtual void Send() override
    {
        while(true)
        {
            int n = send(SockfdVal(),Outstring().c_str(),Outstring().size(),0);
            if( n == 0)
            {
                break;
            }
            else if(n > 0)
            {
                DisCardOutString(n);
            }
            else
            {
                LOG(LogLevel::ERROR)<<"send false";
                 //这两个错误其实是同一个，第一个叫再尝试一次
                 //第二个叫做 挂起了 就是链接着突然对方关闭了链接
                if( errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    //这两个错误码表示缓冲区已满
                    break;
                }
                else if (errno ==EINTR )
                {
                    //这个错误码表示被刚才被系统中断了
                    continue;
                }
                else
                {
                    Execpter();
                }
            }

        }
        //走到这里有两种情况
        //1. outbuffer空了 表示要发送的数据全部发送了（其实是全部拷贝到内核了）
        //2.outbuffer不是空的&&发送缓冲区是满的，写条件不满足，使能epoll的事件发生，直接处理写事件
        if(!IsoutEmpty())
        {
            // 修改对sockfd的事件关心！-- 开启对写事件关心
            // 按需设置！
            GetOwner()->EnableWriteRead(SockfdVal(), true, true);
        }
        else{
            GetOwner()->EnableWriteRead(SockfdVal(), true, false);
        }
    
    }
    virtual void Receiver() override
    {
        char buffer[1024];
        while(true)
        {
            
            int n = recv(SockfdVal(),buffer,sizeof(buffer),0);
            if( n  == 0)
            {
                //对端关闭了
                Execpter();
                break;            
            }
            else if( n > 0)
            {
                LOG(LogLevel::DEBUG)<<"接收成功了";
                buffer[n] = 0 ;
                AppendIn(buffer);
            }
            else 
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    //代表缓冲区是空的 和send的意思是相反的
                    break;       
                }
                else if(errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Execpter();
                    return;
                }
            }
        }

        //此时一定把本轮数据读完了
        std::cout<<"outbuffer is "<<buffer<<std::endl;
        //但是你怎么保证你读到的消息是一个完整的报文
        //所以要用协议保证
        std::string result;
        if(on_message)
        {
            
            result = on_message(InString());
        }
        //如果result不为空的话，就代表reuslt里面存的是应答报文
        
        AppendOut(result);

        //今天简化了，把结果已经存到result里，到outbuffer里了
        //如何处理写的问题，就是把outbuffer里面的数据发送给对方
        if(IsoutEmpty())
        {
            //方案一: Sender(); // 直接发送, 推荐做法
            //方案二: 使能Writeable即可.
            GetOwner()->EnableWriteRead(SockfdVal(),true,true);
        }

    }
    virtual void Execpter() override
    {
        // IO读取的时候，所有的异常处理，全部都会转化成为这个一个函数的调用
        // 出现异常，我们怎么做？？？
        // 打印日志，差错处理，关闭连接，Reactor异常connection, 从内核中，移除对fd的关心
        LOG(LogLevel::INFO)<<"客户端连接可能断开， 进行异常处理";
        GetOwner()->DelConnection(SockfdVal());
    }
    ~IOServer()
    {

    }
    private:
    com_t on_message;
};